package com.seafwg.store.service.impl;

import com.seafwg.store.entity.User;
import com.seafwg.store.mapper.UserMapper;
import com.seafwg.store.service.IUserService;
import com.seafwg.store.service.ex.*;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * @Author seafwg
 * @Date 2022/3/25 2:45 下午
 * @Version 1.0
 * @description xxx
 */
@Service
public class UserServiceImpl implements IUserService {
    // 默认文件大小
    public static final int AVATAR_MAX_SIZE = 10 * 1024 * 1024;
    // 上传图片的类型
    public static final List<String> AVATAR_TYPES = new ArrayList<>();
    // 一加载初始化
    static {
        AVATAR_TYPES.add("image/jpeg");
        AVATAR_TYPES.add("image/png");
        AVATAR_TYPES.add("image/bmp");
        AVATAR_TYPES.add("image/gif");
    }

    @Resource
    private UserMapper userMapper;

    /**
     * 用户注册：
     * @param user
     */
    @Override
    public void register(User user) {
        // 现根据用户名查询是否存在，存在不能注册
        String username = user.getUsername();
        User byUsername = userMapper.findUserByUsername(username);
        if (byUsername != null) {
            throw new UsernameDuplicateException("该"+username+"用户名已存在");
        }

        // 一些数据的填充
        user.setIsDelete(0); // 0：表示未删除，1：已删除
        Date date = new Date();

        user.setCreatedUser(username); // 创建然，创建时间
        user.setCreatedTime(date);
        user.setModifiedUser(username); // 修改人，修改时间
        user.setModifiedTime(date);

        // 密码的加密:
        String password = user.getPassword();
        String salt = UUID.randomUUID().toString().toUpperCase(); // 使用uuid随机生成一个字符串
        String md5Password = getMD5Password(password, salt);
        user.setSalt(salt);
        user.setPassword(md5Password);

        // 保存user对象
        Integer rows = userMapper.insert(user);
        if (rows != 1) {
            throw new InsertException("添加用户出现位置异常");
        }
    }

    /**
     * 用户登录
     * @param user 登录的用户名，密码
     * @return user
     */
    @Override
    public User login(User user) {
        // 1 查询出user信息
        User userByUsername = userMapper.findUserByUsername(user.getUsername());
        // 用户不存在
        if (userByUsername == null) {
            throw new UserNotFoundException("该用户不存在");
        }
        // 该用户已删除
        if (userByUsername.getIsDelete() == 1) {
            throw new UserNotFoundException("该用户不存在");
        }
        // 用户的密码比对
        String password = user.getPassword();
        String salt = userByUsername.getSalt();
        String md5Password = getMD5Password(password, salt);

        if (!userByUsername.getPassword().equals(md5Password)) {
            throw new PasswordNotMatchException("用户密码错误");
        }

        // 返回用户：重新生成一个简介版的用户对象返回，根据前端需要可减轻网络传输压力
        User resultUser = new User();
        resultUser.setUid(userByUsername.getUid());
        resultUser.setUsername(userByUsername.getUsername());
        resultUser.setAvatar(userByUsername.getAvatar());

        return resultUser;
    }

    /**
     * 修改用户密码
     * @param uid 用户uid
     * @param username 用户名
     * @param oldPassword 原有密码
     * @param newPassword 新密码
     */
    @Override
    public void changePassword(Integer uid, String username, String oldPassword, String newPassword) {
        User user = userMapper.findUserByUid(uid);
        // 用户不存在
        if(user == null || user.getIsDelete().equals(1)) {
            throw new UserNotFoundException("该用户不存在");
        }
        // 判断原有密码是否和数据库中的密码一致
        String oldMd5Password = getMD5Password(oldPassword, user.getSalt());
        if(!user.getPassword().equals(oldMd5Password)) {
            throw new PasswordNotMatchException("原有密码错误");
        }
        // 新密码加密，填写修改人，修改时间
        String newMd5Password = getMD5Password(newPassword, user.getSalt());
        Integer rows = userMapper.updateUserPasswordByUid(
                uid,
                newMd5Password,
                username,
                new Date()
        );
        if (rows != 1) {
            throw new UpdatePasswordException("更新用户密码出现异常");
        }
    }

    /**
     * 根据用户uid获取用户对象
     * @param uid 用户uid
     * @return
     */
    @Override
    public User findUserByUid(Integer uid) {
        User user = userMapper.findUserByUid(uid);
        if(user == null || user.getIsDelete().equals(1)) {
            throw new UserNotFoundException("该用户不存在");
        }
        // 重组user对象
        User resUser = new User();
        resUser.setUsername(user.getUsername());
        resUser.setPhone(user.getPhone());
        resUser.setEmail(user.getEmail());
        resUser.setGender(user.getGender());

        return resUser;
    }

    /**
     * 更新用户信息
     * @param uid 用户uid
     * @param username 用户名
     * @param user 用户对象，前端传输参数
     */
    @Override
    public void changeUserInfo(Integer uid, String username, User user) {
        User userByUid = userMapper.findUserByUid(uid);
        if(userByUid == null || userByUid.getIsDelete().equals(1)) {
            throw new UserNotFoundException("该用户不存在");
        }
        // 传递的user对象填充数据
        user.setUid(uid);
        user.setModifiedUser(username);
        user.setModifiedTime(new Date());

        Integer rows = userMapper.updateUserByUid(user);
        if (rows != 1) {
            throw new UpdateUserInfoException("更新用户信息数据时数据库异常");
        }
    }

    /**
     * 根据用户uid修改头像
     * @param uid 用户uid
     * @param username 用户名
     * @param session session对象
     * @param file 上传的file对象
     */
    @Override
    public String changeAvatar(Integer uid, String username, HttpSession session, MultipartFile file) {
        // 检测file的异常信息
        if (file.isEmpty()) {
            throw new FileEmptyException("上传的file为空");
        }
        // file超出文件大小
        if (file.getSize() > AVATAR_MAX_SIZE) {
            throw new FileSizeException("上传文件超出"+ (AVATAR_MAX_SIZE / 1024) + "KB的文件");
        }
        // 文件类型是否匹配
        if (!AVATAR_TYPES.contains(file.getContentType())) {
            throw new FileTypeException("不支持该文件的类型，不允许的文件类型");
        }
        // 文件处理，拿到文件修改文件名，保存到当前项目文件下的/upload/+filename

        // 获取当前项目绝对磁盘路径
        String realPath = session.getServletContext().getRealPath("upload");
        // 创建路径
        File dir = new File(realPath);
        if(!dir.exists()) {
            dir.mkdir();
        }
        // 获取文件保存文件
        String originalFilename = file.getOriginalFilename();
        String[] splitFileName = originalFilename.split(".");
        String suffix = splitFileName[1];

        String filename = UUID.randomUUID().toString() + suffix;
        // 创建文件对象，保存文件对象
        File dest = new File(dir, filename);
        try {
            file.transferTo(dest); // 将文件保存到dest文件目录下
        } catch (IOException e) {
            // e.printStackTrace();
            throw new FileReadWriteIOException("上传文件读写错误，读写出现异常");
        } catch (IllegalStateException e) {
            throw new FileStateException("文件状态异常，可能文件被移动或者删除");
        }

        // 头像路径
        String avatarURL = "/upload/" + filename;


        Integer rows = userMapper.updateUserAvatarByUid(uid, avatarURL, username, new Date());
        if (rows != 1) {
            throw new UpdateAvatarException("更新头像时，数据库异常");
        }
        return avatarURL;
    }



    /**
     * 生成密码加密后的字符串
     * @param password 原始密码
     * @param salt 盐值
     * @return 加密后的密文
     */
    private String getMD5Password(String password, String salt) {
        // 采用三次（salt + password + salt）加密方式加密
        for (int i = 0; i < 3; i++) {
            password = DigestUtils.md5DigestAsHex((salt + password + salt).getBytes()).toUpperCase();
        }
        return password;
    }
}
